using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using WPFPractice.Utils;
using WPFPractice.ViewModels;
using WPFPractice.ViewModels.Draw;

namespace WPFPractice.Windows
{
	/// <summary>
	/// WinAdorners.xaml 的交互逻辑
	/// </summary>
	public partial class WinAdorners : Window
	{
		public WinAdorners()
		{
			InitializeComponent();
			DataContext = new AdornersViewModel();

			_closeButtonFadeoutTimer.Tick += CloseButtonFadeoutTimer_Tick;
			_closeButtonFadeoutTimer.Interval = TimeSpan.FromSeconds(2);
		}

		#region XamlAdorner

		//迁移自：https://gitee.com/DLGCY_Clone/WPF_XamlAdorner 的 AdvancedAdornedControlSample

		private static readonly double FadeOutTime = 1;
		private static readonly double FadeInTime = 0.25;

		private readonly DispatcherTimer _closeButtonFadeoutTimer = new DispatcherTimer();

		private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
		{
			bool wasFadingOut = _fadeOutAnimation != null;
			_fadeOutAnimation = null; // Abort fade out.

			if(_closeButtonFadeoutTimer.IsEnabled)
			{
				Trace.WriteLine("Ellipse_MouseEnter: Stopped fade out delay timer.");

				_closeButtonFadeoutTimer.Stop();
			}

			if(!adornedControl.IsAdornerVisible)
			{
				Trace.WriteLine("Ellipse_MouseEnter: Adorner hidden, fading it in.");

				adornedControl.ShowAdorner();

				DoubleAnimation doubleAnimation2 = new DoubleAnimation(1.0, new Duration(TimeSpan.FromSeconds(FadeInTime)));
				doubleAnimation2.Completed += DoubleAnimation2_Completed;
				adornerCanvas.BeginAnimation(Canvas.OpacityProperty, doubleAnimation2);
			}
			else if(wasFadingOut)
			{
				// Was fading out, fade back in.
				Trace.WriteLine("CloseButton_MouseEnter: Was fading out, fade back in.");

				DoubleAnimation doubleAnimation = new DoubleAnimation(1.0, new Duration(TimeSpan.FromSeconds(FadeInTime)));
				adornerCanvas.BeginAnimation(Canvas.OpacityProperty, doubleAnimation);
			}
			else
			{
				adornerCanvas.BeginAnimation(Canvas.OpacityProperty, null);
			}
		}

		void DoubleAnimation2_Completed(object sender, EventArgs e)
		{
			Trace.WriteLine("DoubleAnimation2_Completed: Finished adorner fade in.");
		}

		private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
		{
			Trace.WriteLine("Ellipse_MouseLeave: Started fade out delay timer.");

			_closeButtonFadeoutTimer.Start();
		}

		DoubleAnimation _fadeOutAnimation = null;

		void CloseButtonFadeoutTimer_Tick(object sender, EventArgs e)
		{
			Trace.WriteLine("CloseButtonFadeoutTimer_Tick: Fade out delay timer elapsed, starting fade out.");

			_closeButtonFadeoutTimer.Stop();

			_fadeOutAnimation = new DoubleAnimation(0.0, new Duration(TimeSpan.FromSeconds(FadeOutTime)));
			_fadeOutAnimation.Completed += DoubleAnimation_Completed;
			adornerCanvas.BeginAnimation(Canvas.OpacityProperty, _fadeOutAnimation);
		}

		void DoubleAnimation_Completed(object sender, EventArgs e)
		{
			if(_fadeOutAnimation == null)
			{
				Trace.WriteLine("DoubleAnimation_Completed: Fade out aborted.");
			}
			else
			{
				Trace.WriteLine("DoubleAnimation_Completed: Fade out complete, hiding the adorner.");

				adornedControl.HideAdorner();

				_fadeOutAnimation = null;
			}
		}

		private void CloseButton_Click(object sender, RoutedEventArgs e)
		{
			canvas.Children.Remove(adornedControl);
		}

		private void CloseButton_MouseEnter(object sender, MouseEventArgs e)
		{
			bool wasFadingOut = _fadeOutAnimation != null;
			_fadeOutAnimation = null; // Abort fade out.

			if(_closeButtonFadeoutTimer.IsEnabled)
			{
				Trace.WriteLine("CloseButton_MouseEnter: Fade out delay timer active, stopping it.");

				_closeButtonFadeoutTimer.Stop();
			}

			Trace.Assert(adornedControl.IsAdornerVisible);

			if(!adornedControl.IsAdornerVisible)
			{
				Trace.WriteLine("CloseButton_MouseEnter: Adorner is hidden, showing it!");

				adornedControl.ShowAdorner();

				DoubleAnimation doubleAnimation = new DoubleAnimation(1.0, new Duration(TimeSpan.FromSeconds(FadeInTime)));
				adornerCanvas.BeginAnimation(Canvas.OpacityProperty, doubleAnimation);
			}
			else if(wasFadingOut)
			{
				// Was fading out, fade back in.
				Trace.WriteLine("CloseButton_MouseEnter: Was fading out, fade back in.");

				DoubleAnimation doubleAnimation = new DoubleAnimation(1.0, new Duration(TimeSpan.FromSeconds(FadeInTime)));
				adornerCanvas.BeginAnimation(Canvas.OpacityProperty, doubleAnimation);
			}
			else
			{
				Trace.WriteLine("CloseButton_MouseEnter: Adorner is not hidden, clearing animation!");

				adornerCanvas.BeginAnimation(Canvas.OpacityProperty, null);
			}
		}

		private void CloseButton_MouseLeave(object sender, MouseEventArgs e)
		{
			Trace.WriteLine("CloseButton_MouseLeave: Started fade out delay timer.");

			_closeButtonFadeoutTimer.Start();
		}

		private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			Canvas.SetLeft(adornedControl, Canvas.GetLeft(adornedControl) + e.HorizontalChange);
			Canvas.SetTop(adornedControl, Canvas.GetTop(adornedControl) + e.VerticalChange);
		}

		#endregion
	}
}

namespace WPFPractice.ViewModels
{
	public class AdornersViewModel : MyBindableBase
	{
		#region 方法

		protected override void InitDataAfterConstruction()
		{
			Console.WriteLine($"演示：可在 Xaml 中添加且支持绑定的 Adorner");
			Console.WriteLine($"1、SmartAdorner，缺点：无法直接设置为显示，会提示找不到 AdornerLayer");
			Console.WriteLine($"2、AdornedControl，缺点：元素隐藏时装饰层仍显示、需使用额外的控件");
			Console.WriteLine($"3、AttachAdornerBehavior");

			for(int i = 0; i < 20; i++)
			{
				var icon = new IconViewModel() { Text = "Icon " + (i + 1), X = (i % 5) * 100 + 10, Y = i / 5 * 120 + 10 };
				Elements.Add(icon);
			}

			Elements.Add(new RectViewModel() { X = 600, Y = 20, Width = 150, Height = 100 });
			Elements.Add(new LineViewModel() { X1 = 610, Y1 = 220, X2 = 760, Y2 = 300 });
		}

		#endregion

		#region 绑定

		public ObservableCollection<Object> Elements { get; set; } = new();

		public string ImageName { get; set; } = "图片";

		#endregion
	}
}
